package server;

import java.io.*;
import java.net.*;
import java.util.*;

public class Server extends Thread {
	private String host;
	private int port;
	private ServerGUI gui;
	private Socket socket;
	private DataOutputStream dout;
	private DataInputStream din;
	private LocalNode localNode;

	private Hashtable outputStreams = new Hashtable();
	// Constructor and while-accept loop all in one.
	public Server( ServerGUI gui, String host, int port, LocalNode ln ) throws IOException {
		// All we have to do is listen
		this.host = host;
		this.port = port;
		this.gui = gui;
		this.localNode = ln;
	}
	
	public void connect(){
		try {
			// Initiate the connection
			socket = new Socket( host, port );
			//Log the connection established
			logNotif("Connection to " + socket + " Successful!", "ALERT");
			//create DataInput/Output streams from socket streams
			din = new DataInputStream( socket.getInputStream() );
			dout = new DataOutputStream( socket.getOutputStream() );
			gui.setConnectStatus(true);
			// Start a background thread for receiving messages
			new Thread( this ).start();
		} catch( IOException ie ) { System.out.println( ie ); }
	}

	public void disconnect(){
		try {
			socket.close();
			gui.setConnectStatus(false);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void run() {
		try {
			// Receive messages one-by-one, forever
			while (true) {
				// Get the next message

				char in = (char)din.read();
				if (in == '[') //Denotes the start of the message
					receiveStatus(in); //Reads every character until the end of the message
				Thread.sleep(17); //Thread sleeps for 17 ms
			}
		} catch( IOException ie ) { System.out.println( ie ); } catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public void receiveStatus(char in) throws IOException, InterruptedException{
		String status = "[";
		while(!status.endsWith("]")){
			in = (char)din.read();					
			status = status.concat(Character.toString(in)); //Adds the character to the end of the string
		}

		localNode.parseStatus(this,status); //Separates the data from the message and stores it in the local node
		//gui.sendToClient();
		gui.saveImage();
		gui.refresh();
	}
	
	
	// Gets called when the user types something
	public void sendMessage( String message ){
		try {
			logln("<SERVER>Sending message: " + message);
			for (int i = 0; i < message.length(); i++){
				byte [] temp = new byte[1];
				temp[0] = (byte)message.charAt(i);
				dout.write(temp,0,1);
				try {
					Thread.sleep(20);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		} catch( IOException ie ) { System.out.println( ie ); }
	}
	
	public void sendCmd( Command cmd, String param){
		String cmdString;
		try {
			cmdString = cmd.sendCmd(localNode, param);
			logln("<SERVER>Sending command: " + cmdString);
			for (int i = 0; i < cmdString.length(); i++){
				byte [] temp = new byte[1];
				temp[0] = (byte)cmdString.charAt(i);
				dout.write(temp,0,1);
				try {
					Thread.sleep(20);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			for (int i = 0; i < 5; i++){
				dout.writeChar(42); //Closing Bracket...
			}
			gui.saveImage();
			//gui.sendToClient();
		} catch( IOException ie ) { System.out.println( ie ); }
	}
	
	public void sendCmd( Command cmd){
		sendCmd(cmd, "0");
	}
	
    public void log (char cmsg){
    	log(Character.toString(cmsg));        		
    }
	
	public void log(String msg){
		gui.log(msg);
	}
	
	public void logMsg(int uid, String src, String dest, String msg){
		String [] temp = {Integer.toString(uid), src, dest, msg};
		String buffer = "";
		for (int i = 0; i < temp.length; i++){
			buffer = buffer.concat("<"+temp[i]+">");
		}
		logln(buffer);
	}
	
	public void logln(String msg){
		gui.log(msg+"\n");
	}
	
	private void logNotif(String msg, String notif) {
		logln("<" + notif + ">"+msg);
	}
	
	public LocalNode getLocalNode(char id){
		if (id == localNode.getLotID())
			return this.localNode;
		else //Fix this for "checking localNode"
			return this.localNode;
	}

	public void setIP(String host, int port) {
		this.host = host;
		this.port = port;
		
	}

	public ServerGUI getGUI() {
		return gui;
	}
	
}